/***************************************************************************************
 *
 *  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 *
 *  By downloading, copying, installing or using the software you agree to this license.
 *  If you do not agree to this license, do not download, install, 
 *  copy or use the software.
 *
 *  Copyright (C) 2014-2019, Happytimesoft Corporation, all rights reserved.
 *
 *  Redistribution and use in binary forms, with or without modification, are permitted.
 *
 *  Unless required by applicable law or agreed to in writing, software distributed 
 *  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 *  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 *  language governing permissions and limitations under the License.
 *
****************************************************************************************/

#include "../bm/sys_inc.h"
#include "file_demux.h"
#include "audio_encoder.h"
#include "video_encoder.h"
#include "media_format.h"
#include "../bm/base64.h"
#include "media_util.h"
#include "../rtp/h264.h"
#include "../rtp/h265.h"


extern "C"
{
	#include <faad.h>
}

/*********************************************************************************/

/**
 * audio data callback, if need re-codec audio data
 */
void AudioCallback(uint8 *data, int size, int nbsamples, void *pUserdata)
{
	CFileDemux * pDemux = (CFileDemux *)pUserdata;

	pDemux->dataCallback(data, size, DATA_TYPE_AUDIO, nbsamples, 1);
}

/**
 * video data callback, if need re-codec video data
 */
void VideoCallback(uint8 *data, int size, void *pUserdata)
{
	CFileDemux * pDemux = (CFileDemux *)pUserdata;

	pDemux->dataCallback(data, size, DATA_TYPE_VIDEO, 0, 1);
}


CFileDemux::CFileDemux(const char * filename, int loopnums)
{
	m_nAudioIndex = -1;
    m_nVideoIndex = -1;
    m_nDuration = 0;
    m_nCurPos = 0;

    m_nNalLength = 0;

    m_pFormatContext = NULL;
    m_pACodecCtx = NULL;    
    m_pVCodecCtx = NULL;
    
    m_pVideoEncoder = NULL;
	m_pAudioEncoder = NULL;

	m_bFirst = TRUE;
	m_pCallback = NULL;
	m_pUserdata = NULL;

    m_nLoopNums = 0;
    m_nMaxLoopNums = loopnums;
    
	init(filename);
}

CFileDemux::~CFileDemux()
{
	uninit();
}

/**
 * Init file demux
 * 
 * @param filename the file name
 * @return TRUE on success, FALSE on error
 */
BOOL CFileDemux::init(const char * filename)
{
	if (avformat_open_input(&m_pFormatContext, filename, NULL, NULL) != 0)
	{
		log_print(LOG_ERR,"----------%s[%d]--------------\n",__FILE__,__LINE__);
        ErrorLog( "avformat_open_input failed, %s\r\n", filename);
		return FALSE;
	}

	avformat_find_stream_info(m_pFormatContext, NULL);

    if (m_pFormatContext->duration != AV_NOPTS_VALUE)
    {
        m_nDuration = m_pFormatContext->duration; 
    }
    
	// find audio & video stream index
	for (uint32 i=0; i < m_pFormatContext->nb_streams; i++)
	{
		if (m_pFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			m_nVideoIndex = i;

			if (m_nDuration < m_pFormatContext->streams[i]->duration) 
            {
                m_nDuration = m_pFormatContext->streams[i]->duration;
            }
		}
		else if (m_pFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
		{
			m_nAudioIndex = i;

			if (m_nDuration < m_pFormatContext->streams[i]->duration) 
            {
                m_nDuration = m_pFormatContext->streams[i]->duration;
            }
		}
	}

    m_nDuration /= 1000; // to millisecond
    
	// has audio stream
	if (m_nAudioIndex != -1)
	{
		m_pACodecCtx = m_pFormatContext->streams[m_nAudioIndex]->codec;
	}

	// has video stream
	if (m_nVideoIndex != -1)
	{
		m_pVCodecCtx = m_pFormatContext->streams[m_nVideoIndex]->codec;

		if (m_pVCodecCtx->codec_id == AV_CODEC_ID_H264)
    	{
    		if (m_pVCodecCtx->extradata && m_pVCodecCtx->extradata_size > 8)
    		{
    		    if (m_pVCodecCtx->extradata[0] == 1)
    		    {
    		        // Store right nal length size that will be used to parse all other nals
                    m_nNalLength = (m_pVCodecCtx->extradata[4] & 0x03) + 1;
    		    }
    		}
    	}
    	else if (m_pVCodecCtx->codec_id == AV_CODEC_ID_HEVC)
    	{
    	    if (m_pVCodecCtx->extradata && m_pVCodecCtx->extradata_size > 8)
    		{
    		    if (m_pVCodecCtx->extradata[0] || m_pVCodecCtx->extradata[1] || m_pVCodecCtx->extradata[2] > 1)
    		    {
                    m_nNalLength = 4;
    		    }
    		}
    	}
	}

	return TRUE;
}


void CFileDemux::uninit()
{
	flushAudio();
	flushVideo();
	
	if (m_pACodecCtx)
	{
		avcodec_close(m_pACodecCtx);
	}
	
	if (m_pVCodecCtx)
	{
		avcodec_close(m_pVCodecCtx);
	}

	if (m_pVideoEncoder)
	{
		delete m_pVideoEncoder;
		m_pVideoEncoder = NULL;
	}
	
	if (m_pAudioEncoder)
	{
		delete m_pAudioEncoder;
		m_pAudioEncoder = NULL;
	}

	if (m_pFormatContext)	
	{
		avformat_close_input(&m_pFormatContext);
	}
}

int CFileDemux::getWidth()
{
	if (m_nVideoIndex != -1)
	{
		return m_pVCodecCtx->width;
	}

	return 0;
}

int CFileDemux::getHeight()
{
	if (m_nVideoIndex != -1)
	{
		return m_pVCodecCtx->height;
	}

	return 0;
}

int CFileDemux::getFramerate() 
{
	int framerate = 25;
	
	if (m_nVideoIndex != -1)
	{
		if (m_pFormatContext->streams[m_nVideoIndex]->r_frame_rate.den > 0)
		{
			framerate = m_pFormatContext->streams[m_nVideoIndex]->r_frame_rate.num / 
						(double)m_pFormatContext->streams[m_nVideoIndex]->r_frame_rate.den;
		}
	}

	return framerate;
}

int CFileDemux::getSamplerate()
{
	if (m_nAudioIndex != -1)
	{
		return m_pACodecCtx->sample_rate;
	}

	return 8000;
}

int CFileDemux::getChannels()
{
	if (m_nAudioIndex != -1)
	{
		return m_pACodecCtx->channels;
	}

	return 2;
}

void CFileDemux::flushVideo()
{
	if (NULL == m_pVCodecCtx || 
		NULL == m_pVCodecCtx->codec || 
		!(m_pVCodecCtx->codec->capabilities | AV_CODEC_CAP_DELAY))
	{
		return;
	}
	
	int got = 0;
	AVPacket pkt;
	
	av_init_packet(&pkt);
	pkt.data = 0;
	pkt.size = 0;

	AVFrame * frame = av_frame_alloc();
	if (NULL == frame)
	{
		return;
	}
		
	int ret = avcodec_decode_video2(m_pVCodecCtx, frame, &got, &pkt);
	while (ret >= 0 && got)
	{
		av_free_packet(&pkt);
		av_frame_free(&frame);

		frame = av_frame_alloc();
		if (NULL == frame)
		{
			break;
		}

		ret = avcodec_decode_video2(m_pVCodecCtx, frame, &got, &pkt);
	}

	av_frame_free(&frame);
}

void CFileDemux::flushAudio()
{
	if (NULL == m_pACodecCtx || 
		NULL == m_pACodecCtx->codec || 
		!(m_pACodecCtx->codec->capabilities | AV_CODEC_CAP_DELAY))
	{
		return;
	}
	
	int got = 0;
	AVPacket pkt;
	
	av_init_packet(&pkt);
	pkt.data = 0;
	pkt.size = 0;

	AVFrame * frame = av_frame_alloc();
	if (NULL == frame)
	{
		return;
	}
		
	int ret = avcodec_decode_audio4(m_pACodecCtx, frame, &got, &pkt);
	while (ret >= 0 && got)
	{
		av_free_packet(&pkt);
		av_frame_free(&frame);

		frame = av_frame_alloc();
		if (NULL == frame)
		{
			break;
		}

		ret = avcodec_decode_audio4(m_pACodecCtx, frame, &got, &pkt);
	}

	av_frame_free(&frame);
}

/**
 * set audio output parameters
 *
 * @param codec audio output codec
 * @param samplerate audio output sample rate
 * @param channels audio output channels
 * @return TRUE on success, FALSE on error
 */
BOOL CFileDemux::setAudioFormat(int codec, int samplerate, int channels, int bitrate)
{
	InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);
	if (m_nAudioIndex == -1)
	{
		InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);
		return FALSE;
	}

#if 0				
	if (m_pACodecCtx->codec_id != CAudioEncoder::toAVCodecID(codec) ||
		m_pACodecCtx->channels != channels ||
		m_pACodecCtx->sample_rate != samplerate ||
		m_pACodecCtx->sample_fmt != AV_SAMPLE_FMT_S16)
#else
	InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);
	if (1)
#endif		
	{
		InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);
		AVCodec * pCodec = avcodec_find_decoder(m_pACodecCtx->codec_id);
		if (pCodec == NULL)
		{
			log_print(LOG_ERR,"----------%s[%d]--------------\n",__FILE__,__LINE__);
			InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);
            ErrorLog( "avcodec_find_decoder failed, %d\r\n", m_pACodecCtx->codec_id);
			return FALSE;
		}
		InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);

		if (avcodec_open2(m_pACodecCtx, pCodec, NULL) != 0)
		{

			log_print(LOG_ERR,"----------%s[%d]--------------\n",__FILE__,__LINE__);
			InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);
            ErrorLog( "avcodec_open2 failed, audio decoder\r\n");
			return FALSE;
		}

		InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);

		m_pAudioEncoder = new CAudioEncoder;
		if (NULL == m_pAudioEncoder)
		{
			InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);
			return FALSE;
		}
		InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);

		AudioEncoderParam params;
		memset(&params, 0, sizeof(params));
		
		params.SrcChannels = m_pACodecCtx->channels;
		params.SrcSamplefmt = m_pACodecCtx->sample_fmt;
		params.SrcSamplerate = m_pACodecCtx->sample_rate;
		params.DstChannels = channels;
		params.DstSamplefmt = AV_SAMPLE_FMT_S16;
		params.DstSamplerate = samplerate;
		params.DstBitrate = bitrate;
		params.DstCodec = codec; //编码方式



		InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);
		if (FALSE == m_pAudioEncoder->init(&params))  //AUDIO_CODEC_G711A
		{
			InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);
			return FALSE;
		}
		InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);

		m_pAudioEncoder->addCallback(AudioCallback, this);
	}
	InfoLog("录像回放: --[%s:%s:%d]--------------\n",__FILE__,__FUNCTION__,__LINE__);
	return TRUE;
}

BOOL CFileDemux::setVideoFormat(int codec, int width, int height, int framerate, int bitrate)
{
	if (m_nVideoIndex == -1)
	{
		return FALSE;
	}
				
	if (m_pVCodecCtx->codec_id != CVideoEncoder::toAVCodecID(codec) || 
		m_pVCodecCtx->width != width ||
		m_pVCodecCtx->height != height)
	{
		AVCodec * pCodec = avcodec_find_decoder(m_pVCodecCtx->codec_id);
		if (pCodec == NULL)
		{
			log_print(LOG_ERR,"----------%s[%d]--------------\n",__FILE__,__LINE__);
            ErrorLog( "avcodec_find_decoder failed, %d\r\n", m_pVCodecCtx->codec_id);
			return FALSE;
		}

		if (avcodec_open2(m_pVCodecCtx, pCodec, NULL) != 0)
		{
			log_print(LOG_ERR,"----------%s[%d]--------------\n",__FILE__,__LINE__);
            ErrorLog( "avcodec_open2 failed, video decoder\r\n");
			return FALSE;
		}

		m_pVideoEncoder = new CVideoEncoder;		
		if (NULL == m_pVideoEncoder)
		{
			return FALSE;
		}

		VideoEncoderParam params;
		memset(&params, 0, sizeof(params));
		
		params.SrcWidth = m_pVCodecCtx->width;
		params.SrcHeight = m_pVCodecCtx->height;
		params.SrcPixFmt = m_pVCodecCtx->pix_fmt;
		params.DstCodec = codec;
		params.DstWidth = width;
		params.DstHeight = height;
		params.DstFramerate = framerate;
		params.DstBitrate = bitrate;
		
		if (FALSE == m_pVideoEncoder->init(&params))
		{
			return FALSE;
		}

		m_pVideoEncoder->addCallback(VideoCallback, this);
	}
	else if (m_pVCodecCtx->codec_id == AV_CODEC_ID_H264)
	{
		const AVBitStreamFilter * bsfc = av_bsf_get_by_name("h264_mp4toannexb");
		if (bsfc) 
		{
			int ret;
			
			AVBSFContext *bsf;
			av_bsf_alloc(bsfc, &bsf);

			ret = avcodec_parameters_from_context(bsf->par_in, m_pVCodecCtx);
	        if (ret < 0)
	        {
	           return FALSE;
			}
			
	        ret = av_bsf_init(bsf);
	        if (ret < 0)
	        {
	            return FALSE;
			}
			
	        ret = avcodec_parameters_to_context(m_pVCodecCtx, bsf->par_out);
	        if (ret < 0)
	        {
	            return FALSE;
			}
			
			av_bsf_free(&bsf);	            
		}
	}	
	else if (m_pVCodecCtx->codec_id == AV_CODEC_ID_HEVC)
	{
		const AVBitStreamFilter * bsfc = av_bsf_get_by_name("hevc_mp4toannexb");
		if (bsfc) 
		{
			int ret;

			AVBSFContext *bsf;
			av_bsf_alloc(bsfc, &bsf);

			ret = avcodec_parameters_from_context(bsf->par_in, m_pVCodecCtx);
	        if (ret < 0)
	        {
	           return FALSE;
			}
			
	        ret = av_bsf_init(bsf);
	        if (ret < 0)
	        {
	            return FALSE;
			}
			
	        ret = avcodec_parameters_to_context(m_pVCodecCtx, bsf->par_out);
	        if (ret < 0)
	        {
	            return FALSE;
			}
			
			av_bsf_free(&bsf);	            
		}
	}

	return TRUE;
}

void CFileDemux::videoRecodec(AVPacket& pkt)
{
	AVFrame * frame;
	int got = 0;
	int remainlen = pkt.size;

	while (remainlen > 0)
	{
		frame = av_frame_alloc();
		if (NULL == frame)
		{
			log_print(LOG_ERR,"----------%s[%d]--------------\n",__FILE__,__LINE__);
            ErrorLog( "av_frame_alloc failed\r\n");
			break;
		}
		
		int len = avcodec_decode_video2(m_pVCodecCtx, frame, &got, &pkt);
		if (len >= 0)
		{
			if (got)
			{
				m_pVideoEncoder->encode(frame);
			}

			pkt.data += len;
			pkt.size -= len;
			remainlen -= len;
		}
		else
		{
			log_print(LOG_ERR,"----------%s[%d]--------------\n",__FILE__,__LINE__);
            ErrorLog( "avcodec_decode_video2, ret = %d\r\n", len);
			
			av_frame_free(&frame);
			break;
		}

		av_frame_free(&frame);
	}
}

void CFileDemux::audioRecodec(AVPacket& pkt)
{
	AVFrame * frame;
	int got = 0;
	int remainlen = pkt.size;

	while (remainlen > 0)
	{
		frame = av_frame_alloc();
		if (NULL == frame)
		{
			log_print(LOG_ERR,"----------%s[%d]--------------\n",__FILE__,__LINE__);
            ErrorLog( "av_frame_alloc failed\r\n");
			break;
		}
		
		int len = avcodec_decode_audio4(m_pACodecCtx, frame, &got, &pkt);
		if (len >= 0)
		{
			if (got)
			{
				m_pAudioEncoder->encode(frame);
			}
			
			pkt.data += len;
			pkt.size -= len;
			remainlen -= len;
		}
		else
		{
			log_print(LOG_ERR,"----------%s[%d]--------------\n",__FILE__,__LINE__);
            ErrorLog( "avcodec_decode_audio4, ret = %d\r\n", len);
			
			av_frame_free(&frame);
			break;
		}

		av_frame_free(&frame);
	}
}

BOOL CFileDemux::readFrame()
{
    int rret = 0;
	AVPacket pkt;
	log_print(LOG_DBG, "readFrame*** :    1-----\n");
	av_init_packet(&pkt);
	pkt.data = 0;
	pkt.size = 0;

	rret = av_read_frame(m_pFormatContext, &pkt);
	InfoLog("readFrame==== rret[%d]\n",rret);
	log_print(LOG_DBG, "readFrame*** :    av_read_frame-----rret[%d]\n",rret);
	if (AVERROR_EOF == rret)
    {
		InfoLog("readFrame==== AVERROR_EOF == rret\n");
/*
        if (++m_nLoopNums >= m_nMaxLoopNums)
        {
			InfoLog("readFrame==== return FALSE\n");
            return FALSE;
        }
        
		rret = av_seek_frame(m_pFormatContext, 0, m_pFormatContext->streams[0]->start_time, 0); //跳转时间
        if (rret < 0)
        {
            rret = av_seek_frame(m_pFormatContext, 0, 0, AVSEEK_FLAG_BYTE | AVSEEK_FLAG_BACKWARD);
            if (rret < 0)
            {
				InfoLog("readFrame==== return FALSE\n");
                return FALSE;
            }
        }
*/
        // avcodec_flush_buffers();
        
        if (av_read_frame(m_pFormatContext, &pkt) != 0)
        {
			log_print(LOG_DBG, "readFrame*** :    readFrame==== return FALSE----\n");
			InfoLog("readFrame==== return FALSE\n");
        	return FALSE;
        }

    }	
	else if (0 != rret)
	{
		InfoLog("readFrame==== return FALSE\n");
		log_print(LOG_DBG, "readFrame*** :    readFrame==== return FALSE2----\n");
		return FALSE;
	}
	log_print(LOG_DBG, "readFrame*** :   2\n");
	if (pkt.stream_index == m_nVideoIndex)
	{
	    AVRational q = {1, AV_TIME_BASE};
        if (pkt.pts != AV_NOPTS_VALUE)
		{
			m_nCurPos = av_rescale_q (pkt.pts, m_pFormatContext->streams[m_nVideoIndex]->time_base, q);

			if (m_pFormatContext->start_time != AV_NOPTS_VALUE)
            {
                m_nCurPos -= m_pFormatContext->start_time;
            }

            m_nCurPos /= 1000;
		}
		else if (pkt.dts != AV_NOPTS_VALUE)
		{
			m_nCurPos = av_rescale_q (pkt.dts, m_pFormatContext->streams[m_nVideoIndex]->time_base, q);

			if (m_pFormatContext->start_time != AV_NOPTS_VALUE)
            {
                m_nCurPos -= m_pFormatContext->start_time;
            }

            m_nCurPos /= 1000;
		}
    		
		if (NULL == m_pVideoEncoder)
		{
			if (m_pVCodecCtx->codec_id == AV_CODEC_ID_H264 ||
				m_pVCodecCtx->codec_id == AV_CODEC_ID_HEVC)
			{
                if (m_nNalLength)
                {
                    while (pkt.size >= m_nNalLength)
					{
						int len = 0;
						int nal_length = m_nNalLength;
						uint8 * data = pkt.data;
						
						while (nal_length--)
						{
                            len = (len << 8) | *data++;
        				}
        				
						if (len > pkt.size - m_nNalLength || len <= 0)
						{
							log_print(LOG_DBG, "readFrame*** :err   len=%d,> pkt.size=%d   || len <= 0\r\n", len, pkt.size);
							//log_print(LOG_ERR,"----------%s[%d]--------------\n",__FILE__,__LINE__);
                            ErrorLog( "len=%d, pkt.size=%d\r\n", len, pkt.size);
							break;
						}

						nal_length = m_nNalLength;
						pkt.data[nal_length-1] = 1;
						nal_length--;
						while (nal_length--)
						{
						    pkt.data[nal_length] = 0;
						}
						
						dataCallback(pkt.data, len+m_nNalLength, DATA_TYPE_VIDEO, 0, pkt.size - len - m_nNalLength >= m_nNalLength ? 0 : 1);

						pkt.data += len + m_nNalLength;
						pkt.size -= len + m_nNalLength;
					}	
                }                
				else if (pkt.data[0] == 0 && pkt.data[1] == 0 && pkt.data[2] == 0 && pkt.data[3] == 1)
				{
					dataCallback(pkt.data, pkt.size, DATA_TYPE_VIDEO, 0, 1);
				}
				else if (pkt.data[0] == 0 && pkt.data[1] == 0 && pkt.data[2] == 1)
				{
					dataCallback(pkt.data, pkt.size, DATA_TYPE_VIDEO, 0, 1);
				}
				else 
				{
					log_print(LOG_DBG, "readFrame*** :err  unknown format\r\n");
					//log_print(LOG_ERR,"----------%s[%d]--------------\n",__FILE__,__LINE__);
                    ErrorLog( "%s, unknown format\r\n", __FUNCTION__);
				}
			}
			else
			{
				dataCallback(pkt.data, pkt.size, DATA_TYPE_VIDEO, 0, 1);				
			}
		}
		else 
		{
			videoRecodec(pkt);
		}
	}
	else if (pkt.stream_index == m_nAudioIndex)
	{
	    AVRational q = {1, AV_TIME_BASE};
        
        if (pkt.pts != AV_NOPTS_VALUE)
		{
			m_nCurPos = av_rescale_q (pkt.pts, m_pFormatContext->streams[m_nAudioIndex]->time_base, q);

			if (m_pFormatContext->start_time != AV_NOPTS_VALUE)
            {
                m_nCurPos -= m_pFormatContext->start_time;
            }

            m_nCurPos /= 1000;
		}
		else if (pkt.dts != AV_NOPTS_VALUE)
		{
			m_nCurPos = av_rescale_q (pkt.dts, m_pFormatContext->streams[m_nAudioIndex]->time_base, q);

			if (m_pFormatContext->start_time != AV_NOPTS_VALUE)
            {
                m_nCurPos -= m_pFormatContext->start_time;
            }

            m_nCurPos /= 1000;
		}
		
		if (NULL == m_pAudioEncoder)
		{
			dataCallback(pkt.data, pkt.size, DATA_TYPE_AUDIO, 0, 1);
		}
		else
		{
			audioRecodec(pkt);
		}
	}
	av_free_packet(&pkt);
	log_print(LOG_DBG, "readFrame*** :end\r\n");
	return TRUE;
}

char * CFileDemux::getH264AuxSDPLine(int rtp_pt)
{
	uint8 * sps = NULL; uint32 spsSize = 0;
	uint8 * pps = NULL; uint32 ppsSize = 0;

	if (NULL == m_pVCodecCtx || m_pVCodecCtx->extradata_size <= 8)
	{
		return NULL;
	}

	uint8 *r, *end = m_pVCodecCtx->extradata + m_pVCodecCtx->extradata_size;
	r = avc_find_startcode(m_pVCodecCtx->extradata, end);

	while (r < end) 
	{
        uint8 *r1;
        
        while (!*(r++));
        r1 = avc_find_startcode(r, end);

        int nal_type = (r[0] & 0x1F);
        
        if (H264_NAL_PPS == nal_type)
        {
            pps = r;
            ppsSize = r1 - r;
        }
        else if (H264_NAL_SPS == nal_type)
        {
            sps = r;
            spsSize = r1 - r;
        }
		
        r = r1;
    }

	if (NULL == sps || spsSize == 0 ||
		NULL == pps || ppsSize == 0)
	{
		return NULL;
	}

	// Set up the "a=fmtp:" SDP line for this stream:
	uint8* spsWEB = new uint8[spsSize]; // "WEB" means "Without Emulation Bytes"
  	uint32 spsWEBSize = remove_emulation_bytes(spsWEB, spsSize, sps, spsSize);
  	if (spsWEBSize < 4) 
  	{
  		// Bad SPS size => assume our source isn't ready
    	delete[] spsWEB;
    	return NULL;
  	}
  	uint8 profileLevelId = (spsWEB[1]<<16) | (spsWEB[2]<<8) | spsWEB[3];
  	delete[] spsWEB;

  	char* sps_base64 = new char[spsSize*2+1];
  	char* pps_base64 = new char[ppsSize*2+1];

	base64_encode(sps, spsSize, sps_base64, spsSize*2+1);
	base64_encode(pps, ppsSize, pps_base64, ppsSize*2+1);
	
  	char const* fmtpFmt =
    	"a=fmtp:%d packetization-mode=1"
    	";profile-level-id=%06X"
    	";sprop-parameter-sets=%s,%s";
    	
  	uint32 fmtpFmtSize = strlen(fmtpFmt)
    	+ 3 /* max char len */
    	+ 6 /* 3 bytes in hex */
    	+ strlen(sps_base64) + strlen(pps_base64);
    	
	char* fmtp = new char[fmtpFmtSize+1];
	memset(fmtp, 0, fmtpFmtSize+1);

  	sprintf(fmtp, fmtpFmt, rtp_pt, profileLevelId, sps_base64, pps_base64);

  	delete[] sps_base64;
  	delete[] pps_base64;

  	return fmtp;
}

char * CFileDemux::getH265AuxSDPLine(int rtp_pt)
{
	uint8* vps = NULL; uint32 vpsSize = 0;
	uint8* sps = NULL; uint32 spsSize = 0;
	uint8* pps = NULL; uint32 ppsSize = 0;

	if (NULL == m_pVCodecCtx || m_pVCodecCtx->extradata_size < 23)
	{
		return NULL;
	}

	uint8 *r, *end = m_pVCodecCtx->extradata + m_pVCodecCtx->extradata_size;
	r = avc_find_startcode(m_pVCodecCtx->extradata, end);

	while (r < end) 
	{
        uint8 *r1;
        
        while (!*(r++));
        r1 = avc_find_startcode(r, end);

        int nal_type = (r[0] >> 1) & 0x3F;
        
        if (HEVC_NAL_VPS == nal_type)
        {
            vps = r;
            vpsSize = r1 - r;
        }
        else if (HEVC_NAL_PPS == nal_type)
        {
            pps = r;
            ppsSize = r1 - r;
        }
        else if (HEVC_NAL_SPS == nal_type)
        {
            sps = r;
            spsSize = r1 - r;
        }
		
        r = r1;
    }
    
	if (NULL == vps || vpsSize == 0 ||
		NULL == sps || spsSize == 0 ||
		NULL == pps || ppsSize == 0)
	{
		return NULL;
	}

	// Set up the "a=fmtp:" SDP line for this stream.
	uint8* vpsWEB = new uint8[vpsSize]; // "WEB" means "Without Emulation Bytes"
	uint32 vpsWEBSize = remove_emulation_bytes(vpsWEB, vpsSize, vps, vpsSize);
	if (vpsWEBSize < 6/*'profile_tier_level' offset*/ + 12/*num 'profile_tier_level' bytes*/)
	{
		// Bad VPS size => assume our source isn't ready
		delete[] vpsWEB;
		return NULL;
	}
	
	uint8 const* profileTierLevelHeaderBytes = &vpsWEB[6];
	uint32 profileSpace  = profileTierLevelHeaderBytes[0]>>6; // general_profile_space
	uint32 profileId = profileTierLevelHeaderBytes[0]&0x1F; 	// general_profile_idc
	uint32 tierFlag = (profileTierLevelHeaderBytes[0]>>5)&0x1;// general_tier_flag
	uint32 levelId = profileTierLevelHeaderBytes[11]; 		// general_level_idc
	uint8 const* interop_constraints = &profileTierLevelHeaderBytes[5];
	char interopConstraintsStr[100];
	sprintf(interopConstraintsStr, "%02X%02X%02X%02X%02X%02X", 
	interop_constraints[0], interop_constraints[1], interop_constraints[2],
	interop_constraints[3], interop_constraints[4], interop_constraints[5]);
	delete[] vpsWEB;

	char* sprop_vps = new char[vpsSize*2+1];
  	char* sprop_sps = new char[spsSize*2+1];
  	char* sprop_pps = new char[ppsSize*2+1];

	base64_encode(vps, vpsSize, sprop_vps, vpsSize*2+1);
  	base64_encode(sps, spsSize, sprop_sps, spsSize*2+1);
	base64_encode(pps, ppsSize, sprop_pps, ppsSize*2+1);

	char const* fmtpFmt =
		"a=fmtp:%d profile-space=%u"
		";profile-id=%u"
		";tier-flag=%u"
		";level-id=%u"
		";interop-constraints=%s"
		";sprop-vps=%s"
		";sprop-sps=%s"
		";sprop-pps=%s";
		
	uint32 fmtpFmtSize = strlen(fmtpFmt)
		+ 3 /* max num chars: rtpPayloadType */ + 20 /* max num chars: profile_space */
		+ 20 /* max num chars: profile_id */
		+ 20 /* max num chars: tier_flag */
		+ 20 /* max num chars: level_id */
		+ strlen(interopConstraintsStr)
		+ strlen(sprop_vps)
		+ strlen(sprop_sps)
		+ strlen(sprop_pps);
		
	char* fmtp = new char[fmtpFmtSize+1];
	memset(fmtp, 0, fmtpFmtSize+1);
	
	sprintf(fmtp, fmtpFmt,
	  	rtp_pt, profileSpace,
		profileId,
		tierFlag,
		levelId,
		interopConstraintsStr,
		sprop_vps,
		sprop_sps,
		sprop_pps);

	delete[] sprop_vps;
	delete[] sprop_sps;
	delete[] sprop_pps;

	return fmtp;
}

char * CFileDemux::getMP4AuxSDPLine(int rtp_pt)
{
	if (NULL == m_pVCodecCtx || m_pVCodecCtx->extradata_size == 0)
	{
		return NULL;
	}
	
	char const* fmtpFmt =
		"a=fmtp:%d "
		"profile-level-id=%d;"
		"config=";
	uint32 fmtpFmtSize = strlen(fmtpFmt)
		+ 3 /* max char len */
		+ 3 /* max char len */
		+ 2*m_pVCodecCtx->extradata_size; /* 2*, because each byte prints as 2 chars */

	char* fmtp = new char[fmtpFmtSize+1];
	memset(fmtp, 0, fmtpFmtSize+1);
	
	sprintf(fmtp, fmtpFmt, rtp_pt, 1);
	char* endPtr = &fmtp[strlen(fmtp)];
	for (int i = 0; i < m_pVCodecCtx->extradata_size; ++i) 
	{
		sprintf(endPtr, "%02X", m_pVCodecCtx->extradata[i]);
		endPtr += 2;
	}

	return fmtp;
}

char * CFileDemux::getVideoAuxSDPLine(int rtp_pt)
{
	if (m_pVideoEncoder)
	{
		return m_pVideoEncoder->getAuxSDPLine(rtp_pt);
	}
	
	if (m_pVCodecCtx->codec_id == AV_CODEC_ID_H264)
	{
		return getH264AuxSDPLine(rtp_pt);		
	}
	else if (m_pVCodecCtx->codec_id == AV_CODEC_ID_MPEG4)
	{
		return getMP4AuxSDPLine(rtp_pt);
	}
	else if (m_pVCodecCtx->codec_id == AV_CODEC_ID_HEVC)
	{
		return getH265AuxSDPLine(rtp_pt);
	}

	return NULL;  	
}

char * CFileDemux::getAACAuxSDPLine(int rtp_pt)
{
	if (NULL == m_pACodecCtx || m_pACodecCtx->extradata_size == 0)
	{
		return NULL;
	}
	
	char const* fmtpFmt =
        "a=fmtp:%d "
    	"streamtype=5;profile-level-id=1;"
    	"mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;"
    	"config="; /* streamtype, 4 : video, 5 : audio */
	uint32 fmtpFmtSize = strlen(fmtpFmt)
	    + 3 /* max char len */
	    + 2*m_pACodecCtx->extradata_size; /* 2*, because each byte prints as 2 chars */

	char* fmtp = new char[fmtpFmtSize+1];
	memset(fmtp, 0, fmtpFmtSize+1);
	
	sprintf(fmtp, fmtpFmt, rtp_pt);
	char* endPtr = &fmtp[strlen(fmtp)];
	for (int i = 0; i < m_pACodecCtx->extradata_size; ++i) 
	{
		sprintf(endPtr, "%02X", m_pACodecCtx->extradata[i]);
		endPtr += 2;
	}

	return fmtp;
}

char * CFileDemux::getAudioAuxSDPLine(int rtp_pt)
{
	if (m_pAudioEncoder)
	{
		return m_pAudioEncoder->getAuxSDPLine(rtp_pt);
	}
	
	if (m_pACodecCtx->codec_id == AV_CODEC_ID_AAC)
	{
		return getAACAuxSDPLine(rtp_pt);		
	}

	return NULL;  	
}

BOOL CFileDemux::seekStream(double pos)
{
    if (pos < 0)
    {
        return FALSE;
    }

    if (pos == m_nCurPos)
    {
    	return TRUE;
    }

    int stream = -1;
    int64 seekpos = pos * 1000000;
    
    if (m_nVideoIndex >= 0)
    {
        stream = m_nVideoIndex;
    }    
    else if (m_nAudioIndex >= 0)
    {
        stream = m_nAudioIndex;
    }

    if (m_pFormatContext->start_time != AV_NOPTS_VALUE)
    {
        seekpos += m_pFormatContext->start_time;
    }

    if (stream >= 0)
    {
        AVRational q = {1, AV_TIME_BASE}; 
        
        seekpos = av_rescale_q(seekpos, q, m_pFormatContext->streams[stream]->time_base);
    }

    if (av_seek_frame(m_pFormatContext, stream, pos, AVSEEK_FLAG_BACKWARD) < 0)
    { 
        return FALSE;
    }

    // Accurate seek to the specified position
    AVPacket pkt;
	
	av_init_packet(&pkt);
	pkt.data = 0;
	pkt.size = 0;
	
    while (av_read_frame(m_pFormatContext, &pkt) == 0)
    {
		if (pkt.stream_index != stream)
		{
			av_free_packet(&pkt);
			continue;
		}
		
        if (pkt.pts != AV_NOPTS_VALUE)
		{
			if (pkt.pts < seekpos)
			{
				av_free_packet(&pkt);
				continue;
			}
			else
			{
			    break;
			}
		}
		else if (pkt.dts != AV_NOPTS_VALUE)
		{
			if (pkt.dts < seekpos)
			{
				av_free_packet(&pkt);
				continue;
			}
			else
			{
			    break;
			}
		}
		else
		{
			break;
		}
        
        av_free_packet(&pkt);
    }

	av_free_packet(&pkt);
	
    m_nCurPos = pos * 1000;

    return TRUE;
}



typedef struct
{
    int write_adts;
    int objecttype;
    int sample_rate_index;
    int channel_conf;
}ADTSContext;


int aac_decode_extradata(ADTSContext *adts, unsigned char *pbuf, int bufsize)
{
    int aot, aotext, samfreindex;
    int i, channelconfig;
    unsigned char *p = pbuf;
    if (!adts || !pbuf || bufsize<2)
    {
        return -1;
    }
    aot = (p[0]>>3)&0x1f;
    if (aot == 31)
    {
        aotext = (p[0]<<3 | (p[1]>>5)) & 0x3f;
        aot = 32 + aotext;
        samfreindex = (p[1]>>1) & 0x0f;
        if (samfreindex == 0x0f)
        {
            channelconfig = ((p[4]<<3) | (p[5]>>5)) & 0x0f;
        }
        else
        {
            channelconfig = ((p[1]<<3)|(p[2]>>5)) & 0x0f;
        }
    }
    else
    {
        samfreindex = ((p[0]<<1)|p[1]>>7) & 0x0f;
        if (samfreindex == 0x0f)
        {
            channelconfig = (p[4]>>3) & 0x0f;
        }
        else
        {
            channelconfig = (p[1]>>3) & 0x0f;
        }
    }
#ifdef AOT_PROFILE_CTRL
    if (aot < 2) aot = 2;
#endif
    adts->objecttype = aot-1;
    adts->sample_rate_index = samfreindex;
    adts->channel_conf = channelconfig;
    adts->write_adts = 1;
    return 0;
}


#define  ADTS_HEADER_SIZE 7

int aac_set_adts_head(ADTSContext *acfg, unsigned char *buf, int size)
{
    unsigned char byte;
    if (size < ADTS_HEADER_SIZE)
    {
        return -1;
    }
    buf[0] = 0xff;
    buf[1] = 0xf1;
    byte = 0;
    byte |= (acfg->objecttype & 0x03) << 6;
    byte |= (acfg->sample_rate_index & 0x0f) << 2;
    byte |= (acfg->channel_conf & 0x07) >> 2;
    buf[2] = byte;
    byte = 0;
    byte |= (acfg->channel_conf & 0x07) << 6;
    byte |= (ADTS_HEADER_SIZE + size) >> 11;
    buf[3] = byte;

    byte = 0;
    byte |= (ADTS_HEADER_SIZE + size) >> 3;  //
    buf[4] = byte;

    byte = 0;
    byte |= ((ADTS_HEADER_SIZE + size) & 0x7) << 5;  //
    byte |= (0x7ff >> 6) & 0x1f;
    buf[5] = byte;

    byte = 0;
    byte |= (0x7ff & 0x3f) << 2;
    buf[6] = byte;
    return 0;
}


//
NeAACDecHandle   g_aacDecoder = NULL;


void CFileDemux::dataCallback(uint8 * data, int size, int type, int nbsamples, BOOL waitnext)
{

	if (m_pCallback)
	{
		uint8 * buff = data;
		int len = size;

		InfoLog("aaaaaaaaaaaaaaaaaaaaaaa------->>>>type=%d========\n",type);

		if (DATA_TYPE_VIDEO == type)   //1
		{

			if( (m_pVCodecCtx->codec_id == AV_CODEC_ID_H264) &&
				//(data[4] & 0x1F) == 5 &&
				(m_pVCodecCtx->extradata_size > 0))
			{
				len = m_pVCodecCtx->extradata_size + size;
				buff = (uint8 *)malloc(len);
				if (buff)
				{
					memcpy(buff, m_pVCodecCtx->extradata, m_pVCodecCtx->extradata_size);
					memcpy(buff + m_pVCodecCtx->extradata_size, data, size);
				}
				else
				{
					buff = data;
					len = size;
				}
			}

		}
		else if(DATA_TYPE_AUDIO == type) //0
		{

           // ff_adts_write_frame_header();
			// m_pVCodecCtx->codec_id = 27
			// AV_CODEC_ID_AAC = 86018
			InfoLog("aaaaaaaaaaaaaaaaaaaaaaa------->>>>m_pACodecCtx->codec_id=%d=== AV_CODEC_ID_AAC=%d====\n",m_pACodecCtx->codec_id,AV_CODEC_ID_AAC);
			InfoLog("aaaaaaaaaaaaaaaaaaaaaaa------->>>>len=%d========\n",len);

			if( ( AV_CODEC_ID_AAC == m_pACodecCtx->codec_id ) &&
			    (m_pACodecCtx->extradata_size > 0) )
			{
#if 1
				len = size;
				buff = (uint8 *)malloc(len);
				memset(buff,0,len);
				if (buff)
				{
					memcpy(buff , data, size);
                }
				else
				{
					buff = data;
					len = size;
				}
#else

				//buff   len
				len = m_pACodecCtx->extradata_size + size+7-2; ////增加 AAC 头的信息 7个长度，去掉2个原始的AAC头
				buff = (uint8 *)malloc(len);
				memset(buff,0,len);
				if (buff)
				{
					//memcpy(buff, m_pACodecCtx->extradata, m_pACodecCtx->extradata_size);
					//memcpy(buff + m_pACodecCtx->extradata_size, data, size);

					//增加 AAC 头的信息
                    ADTSContext AdtsCtx;
                    aac_decode_extradata(&AdtsCtx, m_pACodecCtx->extradata, m_pACodecCtx->extradata_size);
                    unsigned char pAdts [7] = {0};
                    aac_set_adts_head(&AdtsCtx, pAdts, size);

                    memcpy(&buff[0], pAdts, 7);
                    memcpy(&buff[7], data, size);
#endif
			}


		}
        printf("cccccccccccccccccccc CFileDemux::dataCallback =[%d] cccccccccccccccccccc\n",pthread_self());

		m_pCallback(buff, len, type, nbsamples, waitnext, m_pUserdata);

		if (buff != data)
		{
			free(buff);
		}
	}

}

void CFileDemux::setCallback(DemuxCallback pCallback, void * pUserdata)
{
	m_pCallback = pCallback;
	m_pUserdata = pUserdata;
}

